home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 17
/
CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso
/
CUCD
/
Programming
/
DiceSource
/
src
/
dutil
/
dprof.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-09-09
|
11KB
|
472 lines
/*
* (c)Copyright 1992-1997 Obvious Implementations Corp. Redistribution and
* use is allowed under the terms of the DICE-LICENSE FILE,
* DICE-LICENSE.TXT.
*/
/*
* DPROF.C
*
* DPROF <dproffile> [-call]
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#ifdef AMIGA
#include <lib/profile.h>
#include <lib/version.h>
#include <lib/muldiv.h>
#else
#include <include/lib/profile.h>
#include <include/lib/version.h>
#include <include/lib/muldiv.h>
#endif
ProfSym **ProfAry;
ProfSym *ProfList;
ProfSym *ProfData;
void DumpProfInfo(void);
void DumpProfInfoFrom(ProfSym *);
void DumpProfTree(long, ProfSym *, short, long);
void DumpCombineProfTree(ProfSym *);
void SortProfList(void);
void help(int);
char *NameOf(ProfSym *);
short NoLoop(ProfSym *, ProfSym *);
unsigned long TimeBase;
short MaxSymLen;
short CallTreeOpt;
char FileName[256];
IDENT("dprof", ".1");
DCOPYRIGHT;
main(ac, av)
char *av[];
{
int fd;
short i;
ProfHdr phdr;
for (i = 1; i < ac; ++i) {
char *ptr = av[i];
if (*ptr != '-') {
strcpy(FileName, ptr);
continue;
}
ptr += 2;
switch(ptr[-1]) {
case 'c':
CallTreeOpt = 1;
break;
default:
help(0);
}
}
if (FileName[0] == 0)
help(0);
strcat(FileName, ".dprof");
if ((fd = open(FileName, O_RDONLY|O_BINARY)) < 0) {
FileName[strlen(FileName) - 6] = 0;
if ((fd = open(FileName, O_RDONLY|O_BINARY)) < 0) {
printf("Unable to open %s\n", FileName);
exit(10);
}
}
if (read(fd, &phdr, sizeof(phdr)) != sizeof(phdr) || phdr.ph_Magic != PROF_MAGIC) {
printf("%s not a dprof file\n", FileName);
exit(20);
}
if ((ProfAry = malloc(phdr.ph_NumIds * sizeof(ProfSym *))) == NULL) {
puts("no memory");
exit(20);
}
TimeBase = phdr.ph_TimeBase;
clrmem(ProfAry, phdr.ph_NumIds * sizeof(ProfSym *));
{
long n;
ProfSym *ps;
n = lseek(fd, 0L, 2);
if ((ProfData = malloc(n)) == NULL) {
puts("no memory!");
exit(20);
}
lseek(fd, 0L, 0);
if (read(fd, ProfData, n) != n) {
printf("read error\n");
exit(20);
}
for (ps = (ProfSym *)((ProfHdr *)ProfData + 1); (char *)ps < ((char *)ProfData + n); ps = (ProfSym *)((char *)ps + ps->ps_Size)) {
long i = ps->ps_Id;
ps->ps_TimeStamp = 0;
ps->ps_AccumTime = 0;
if (i < 0 || i >= phdr.ph_NumIds) {
printf("illegal id: %d\n", i);
exit(20);
}
ProfAry[i] = ps;
if (ps->ps_FuncName[0]) {
short len;
ps->ps_Link = ProfList;
ProfList = ps;
if ((len = strlen(ps->ps_FuncName)) > MaxSymLen)
MaxSymLen = len;
} else if (ProfList) {
ps->ps_SibLink = ProfList->ps_SibLink;
ProfList->ps_SibLink = ps;
}
}
for (ps = (ProfSym *)((ProfHdr *)ProfData + 1); (char *)ps < ((char *)ProfData + n); ps = (ProfSym *)((char *)ps + ps->ps_Size)) {
if (ps->ps_Parent)
ps->ps_Parent = ProfAry[(long)ps->ps_Parent];
}
}
printf("\n%s\t\t%s\n\n", Ident, FileName);
DumpProfInfo();
return(0);
}
void
help(code)
{
printf("%s\n%s\n", Ident, DCopyright);
exit(code);
}
void
DumpProfInfo()
{
ProfSym *ps;
unsigned long grandTotal = 0;
/*
* Id for quick name reference
*/
for (ps = ProfList; ps; ps = ps->ps_Link) {
ProfSym *ps2;
for (ps2 = ps; ps2; ps2 = ps2->ps_SibLink)
ps2->ps_Id = ps->ps_Id;
}
/*
* AccumTime total time used by node & subroutines for all instances
* (only good in header node of proflist)
*
* TotalTime total time used by node & subroutines
*
* TimeStamp local time used by this node only
*/
for (ps = ProfList; ps; ps = ps->ps_Link) {
ProfSym *ps2;
long total = 0;
long calls = 0;
if (ps->ps_Parent == NULL)
grandTotal += ps->ps_TotalTime;
for (ps2 = ps; ps2; ps2 = ps2->ps_SibLink) {
if (NoLoop(ps, ps2))
total += ps2->ps_TotalTime;
if (ps2->ps_Parent)
ps2->ps_Parent->ps_TimeStamp += ps2->ps_TotalTime;
}
ps->ps_AccumTime = total;
}
for (ps = ProfList; ps; ps = ps->ps_Link) {
ProfSym *ps2;
for (ps2 = ps; ps2; ps2 = ps2->ps_SibLink)
ps2->ps_TimeStamp = ps2->ps_TotalTime - ps2->ps_TimeStamp;
}
printf("GrandTotal: %5ld.%02d mS\n",
MulDivU(grandTotal, 1000, TimeBase), MulDivU(grandTotal, 100000, TimeBase) % 100,
);
printf("\n**** BY ROUTINE ****\n\n");
/*
* sort by total time
*/
SortProfList();
/*
* display master statistics
*/
for (ps = ProfList; ps; ps = ps->ps_Link) {
ProfSym *ps2;
long total = 0;
long local = 0;
long calls = 0;
for (ps2 = ps; ps2; ps2 = ps2->ps_SibLink) {
if (NoLoop(ps, ps2))
total += ps2->ps_TotalTime;
local += ps2->ps_TimeStamp;
calls += ps2->ps_NumCalls;
}
printf("%-*s calls=%-6d ", MaxSymLen, ps->ps_FuncName, calls);
printf("total=%5ld.%02d mS (%3d.%02d%%) local=%5ld.%02d mS (%3d.%02d%%)\n",
MulDivU(total, 1000, TimeBase), MulDivU(total, 100000, TimeBase) % 100,
MulDivU(total, 100, grandTotal), MulDivU(total, 10000, grandTotal) % 100,
MulDivU(local, 1000, TimeBase), MulDivU(local, 100000, TimeBase) % 100,
MulDivU(local, 100, grandTotal), MulDivU(local, 10000, grandTotal) % 100
);
}
printf("\n**** BY PARENT ****\n\n");
for (ps = ProfList; ps; ps = ps->ps_Link) {
if (ps->ps_SibLink)
DumpProfInfoFrom(ps);
}
printf("\n**** COMBINED CALL TREE ****\n\n");
for (ps = ProfList; ps; ps = ps->ps_Link)
DumpCombineProfTree(ps);
if (CallTreeOpt) {
printf("\n**** CALL TREE ****\n\n");
for (ps = ProfList; ps; ps = ps->ps_Link) {
if (ps->ps_Parent == NULL)
DumpProfTree(ps->ps_TotalTime, ps, 0, 32768);
}
}
}
void
DumpProfInfoFrom(ps)
ProfSym *ps;
{
ProfSym *ps2;
long total = 0;
long calls = 0;
for (ps2 = ps; ps2; ps2 = ps2->ps_SibLink) {
if (NoLoop(ps, ps2))
total += ps2->ps_TotalTime;
calls += ps2->ps_NumCalls;
}
printf("%-*s calls=%-6d ", MaxSymLen, ps->ps_FuncName, calls);
printf("total=%5ld.%02d mS\n",
MulDivU(total, 1000, TimeBase), MulDivU(total, 100000, TimeBase) % 100
);
for (ps2 = ps; ps2; ps2 = ps2->ps_SibLink) {
printf(" From %-*s calls=%-6d ", MaxSymLen, NameOf(ps2->ps_Parent), ps2->ps_NumCalls);
printf("total=%5ld.%02d mS (%3d.%02d%%)\n",
MulDivU(ps2->ps_TotalTime, 1000, TimeBase), MulDivU(ps2->ps_TotalTime, 100000, TimeBase) % 100,
MulDivU(ps2->ps_TotalTime, 100, total), MulDivU(ps2->ps_TotalTime, 10000, total) % 100
);
}
}
void
DumpProfTree(total, ps, tab, limit)
long total;
ProfSym *ps;
short tab;
long limit;
{
ProfSym *ps1;
ProfSym *ps2;
short cnt = 0;
printf("%*.*s%-*s calls=%-5ld tot=%5ld.%02d (%3d.%02d) loc=%5ld.%02d (%3d.%02d)",
tab, tab, "",
MaxSymLen, NameOf(ps),
ps->ps_NumCalls,
MulDivU(ps->ps_TotalTime, 1000, TimeBase), MulDivU(ps->ps_TotalTime, 100000, TimeBase) % 100,
MulDivU(ps->ps_TotalTime, 100, total), MulDivU(ps->ps_TotalTime, 10000, total) % 100,
MulDivU(ps->ps_TimeStamp, 1000, TimeBase), MulDivU(ps->ps_TimeStamp, 100000, TimeBase) % 100,
MulDivU(ps->ps_TimeStamp, 100, total), MulDivU(ps->ps_TimeStamp, 10000, total) % 100
);
if (limit) {
for (ps1 = ProfList; ps1; ps1 = ps1->ps_Link) {
for (ps2 = ps1; ps2; ps2 = ps2->ps_SibLink) {
if (ps2->ps_Parent == ps) {
if (cnt == 0)
puts(" {");
DumpProfTree(total, ps2, tab + 4, limit - 1);
++cnt;
}
}
}
}
if (cnt)
printf("%*.*s}\n", tab, tab, "");
else
puts("");
}
void
DumpCombineProfTree(ps)
ProfSym *ps;
{
ProfSym *ps2;
ProfSym *ps3;
long total = 0;
long local = 0;
long calls = 0;
for (ps2 = ps; ps2; ps2 = ps2->ps_SibLink) {
if (NoLoop(ps, ps2))
total += ps2->ps_TotalTime;
calls += ps2->ps_NumCalls;
local += ps2->ps_TimeStamp;
}
if (calls == 0)
return;
printf("%-*s calls=%-5ld tot=%5ld.%02d (%3d.%02d) loc=%5ld.%02d (%3d.%02d)\n",
MaxSymLen, NameOf(ps),
calls,
MulDivU(total, 1000, TimeBase), MulDivU(total, 100000, TimeBase) % 100,
MulDivU(total, 100, total), MulDivU(total, 10000, total) % 100,
MulDivU(local, 1000, TimeBase), MulDivU(local, 100000, TimeBase) % 100,
MulDivU(local, 100, total), MulDivU(local, 10000, total) % 100
);
/*
* find all routines this routine explicitly calls
*/
for (ps2 = ProfList; ps2; ps2 = ps2->ps_Link) {
long subTotal = 0;
long subLocal = 0;
long subCalls = 0;
/*
* add totals for routines that we (ps) call. For each ps2 element
* check to see if it is called by ps.
*/
for (ps3 = ps2; ps3; ps3 = ps3->ps_SibLink) {
if (ps3->ps_Parent && ps3->ps_Parent->ps_Id == ps->ps_Id) {
subTotal += ps3->ps_TotalTime;
subCalls += ps3->ps_NumCalls;
subLocal += ps3->ps_TimeStamp;
/*
* Scan the baselist backwards looking for this ps3.
* If found then subtract the base total entry from
* the subTotal since (1) the base is already counted
* and (2) its subroutines have been or will be counted
*
* B
* \
* Y Y's total
* \
* B should not include B
*/
{
ProfSym *ps4;
ProfSym *ps5;
for (ps4 = ps; ps4; ps4 = ps4->ps_SibLink) {
for (ps5 = ps4->ps_Parent; ps5; ps5 = ps5->ps_Parent) {
if (ps5->ps_Id == ps->ps_Id)
break;
if (ps5 == ps3) {
subTotal -= ps4->ps_TotalTime;
break;
}
}
}
}
}
}
if (subCalls) {
if (ps2->ps_Id == ps->ps_Id) {
printf(" %-*s calls=%-5ld\n",
MaxSymLen, "<SELF>",
subCalls
);
} else {
printf(" %-*s calls=%-5ld tot=%5ld.%02d (%3d.%02d) loc=%5ld.%02d (%3d.%02d)\n",
MaxSymLen, NameOf(ps2),
subCalls,
MulDivU(subTotal, 1000, TimeBase), MulDivU(subTotal, 100000, TimeBase) % 100,
MulDivU(subTotal, 100, total), MulDivU(subTotal, 10000, total) % 100,
MulDivU(subLocal, 1000, TimeBase), MulDivU(subLocal, 100000, TimeBase) % 100,
MulDivU(subLocal, 100, total), MulDivU(subLocal, 10000, total) % 100
);
}
}
}
}
char *
NameOf(psc)
ProfSym *psc;
{
if (psc == NULL)
return("<root>");
return(ProfAry[psc->ps_Id]->ps_FuncName);
}
void
SortProfList()
{
ProfSym *ps;
ProfSym *psnext;
ProfSym **pp;
long total = 0;
for (ps = ProfList, ProfList = NULL; ps; ps = psnext) {
psnext = ps->ps_Link;
for (pp = &ProfList; *pp; pp = &(*pp)->ps_Link) {
if (ps->ps_AccumTime > (*pp)->ps_AccumTime)
break;
}
ps->ps_Link = *pp;
*pp = ps;
}
}
/*
* Ensure that no parent of node is in the baselist
*/
short
NoLoop(base, node)
ProfSym *base;
ProfSym *node;
{
if (node) {
while (node = node->ps_Parent) {
if (node->ps_Id == base->ps_Id)
return(0);
}
}
return(1);
}